Vincent Bernat: Switching to the i3 window manager
I have been using the awesome window manager for 10 years. It is a
tiling window manager, configurable and extendable with the
Lua language. Using a general-purpose programming language to
configure every aspect is a double-edged sword. Due to laziness and
the apparent difficulty of adapting my configuration about 3000 lines to newer releases, I was stuck with the 3.4
version, whose last release is from 2013.
It was time for a rewrite. Instead, I have switched to the i3 window
manager, lured by the possibility to migrate to Wayland and
Sway later with minimal pain. Using an embedded interpreter for
configuration is not as important to me as it was in the past: it
brings both complexity and brittleness.
The window manager is only one part of a desktop environment. There
are several options for the other components. I am also introducing
them in this post.
i3: the window manager
i3 aims to be a minimal tiling window manager. Its documentation
can be read from top to bottom in less than an hour. i3 organize
windows in a tree. Each non-leaf node contains one or several
windows and has an orientation and a layout. This information
arbitrates the window positions. i3 features three layouts: split,
stacking, and tabbed. They are demonstrated in the below screenshot:
Most of the other tiling window managers, including the awesome
window manager, use predefined layouts. They usually feature a large
area for the main window and another area divided among the remaining
windows. These layouts can be tuned a bit, but you mostly stick to a
couple of them. When a new window is added, the behavior is quite
predictable. Moreover, you can cycle through the various windows
without thinking too much as they are ordered.
i3 is more flexible with its ability to build any layout on the fly,
it can feel quite overwhelming as you need to visualize the tree in
your head. At first, it is not unusual to find yourself with a complex
tree with many useless nested containers. Moreover, you have to
navigate windows using directions. It takes some time to get used to.
I set up a split layout for Emacs and a few terminals, but most of the
other workspaces are using a tabbed layout. I don t use the stacking
layout. You can find many scripts trying to emulate other tiling
window managers but I did try to get my setup pristine of these
tentatives and get a chance to familiarize myself. i3 can also save
and restore layouts, which is quite a powerful feature.
My configuration is quite similar to the default one and has
less than 200 lines.
i3: the window manager
i3 aims to be a minimal tiling window manager. Its documentation
can be read from top to bottom in less than an hour. i3 organize
windows in a tree. Each non-leaf node contains one or several
windows and has an orientation and a layout. This information
arbitrates the window positions. i3 features three layouts: split,
stacking, and tabbed. They are demonstrated in the below screenshot:
Most of the other tiling window managers, including the awesome
window manager, use predefined layouts. They usually feature a large
area for the main window and another area divided among the remaining
windows. These layouts can be tuned a bit, but you mostly stick to a
couple of them. When a new window is added, the behavior is quite
predictable. Moreover, you can cycle through the various windows
without thinking too much as they are ordered.
i3 is more flexible with its ability to build any layout on the fly,
it can feel quite overwhelming as you need to visualize the tree in
your head. At first, it is not unusual to find yourself with a complex
tree with many useless nested containers. Moreover, you have to
navigate windows using directions. It takes some time to get used to.
I set up a split layout for Emacs and a few terminals, but most of the
other workspaces are using a tabbed layout. I don t use the stacking
layout. You can find many scripts trying to emulate other tiling
window managers but I did try to get my setup pristine of these
tentatives and get a chance to familiarize myself. i3 can also save
and restore layouts, which is quite a powerful feature.
My configuration is quite similar to the default one and has
less than 200 lines.
i3 companion: the missing bits
i3 philosophy is to keep a minimal core and let the user implements
missing features using the IPC protocol:
Do not add further complexity when it can be avoided. We are
generally happy with the feature set of i3 and instead focus on
fixing bugs and maintaining it for stability. New features will
therefore only be considered if the benefit outweighs the additional
complexity, and we encourage users to implement features using the
IPC whenever possible.
Introduction to the i3 window manager
While this is not as powerful as an embedded language, it is enough
for many cases. Moreover, as high-level features may be opinionated,
delegating them to small, loosely coupled pieces of code keeps them
more maintainable. Libraries exist for this purpose in several
languages. Users have published many scripts to extend i3:
automatic layout and window promotion to mimic the behavior
of other tiling window managers, window swallowing to put a new
app on top of the terminal launching it, and cycling between
windows with Alt+Tab.
Instead of maintaining a script for each feature, I have centralized
everything into a single Python process,
i3-companion
using asyncio and the
i3ipc-python library. Each feature is self-contained into a
function. It implements the following components:
- make a workspace exclusive to an application
- When a workspace contains Emacs or Firefox, I would like other
applications to move to another workspace, except for the terminal
which is allowed to intrude into any workspace. The
workspace_exclusive()
function monitors new windows and moves them
if needed to an empty workspace or to one with the same application
already running.
- implement a Quake console
- The
quake_console()
function implements a drop-down console
available from any workspace. It can be toggled with
Mod+ . This is implemented as a scratchpad
window.
- back and forth workspace switching on the same output
- With the
workspace back_and_forth
command, we can ask i3 to
switch to the previous workspace. However, this feature is not
restricted to the current output. I prefer to have one keybinding to
switch to the workspace on the next output and one keybinding to
switch to the previous workspace on the same output. This behavior
is implemented in the previous_workspace()
function by keeping a
per-output history of the focused workspaces.
- create a new empty workspace or move a window to an empty workspace
- To create a new empty workspace or move a window to an empty
workspace, you have to locate a free slot and use
workspace number
4
or move container to workspace number 4
. The new_workspace()
function finds a free number and use it as the target workspace.
- restart some services on output change
- When adding or removing an output, some actions need to be executed:
refresh the wallpaper, restart some components unable to adapt their
configuration on their own, etc. i3 triggers an event for this
purpose. The
output_update()
function also takes an extra step to
coalesce multiple consecutive events and to check if there is a real
change with the low-level library xcffib.
I will detail the other features as this post goes on. On the
technical side, each function is decorated with the events it should
react to:
@on(CommandEvent("previous-workspace"), I3Event.WORKSPACE_FOCUS)
async def previous_workspace(i3, event):
"""Go to previous workspace on the same output."""
The CommandEvent()
event class is my way to send a command to the
companion, using either i3-msg -t send_tick
or binding a key to a
nop
command. The latter is used to avoid spawning a shell and a
i3-msg
process just to send a message. The companion listens to
binding events and checks if this is a nop
command.
bindsym $mod+Tab nop "previous-workspace"
There are other decorators to avoid code duplication: @debounce()
to
coalesce multiple consecutive calls, @static()
to define a static
variable, and @retry()
to retry a function on failure. The whole
script is a bit more than 1000 lines. I think this is
worth a read as I am quite happy with the result.
dunst: the notification daemon
Unlike the awesome window manager, i3 does not come with a built-in
notification system. Dunst is a lightweight notification daemon. I
am running a modified version with HiDPI support for X11 and
recursive icon lookup. The i3 companion has a helper function,
notify()
, to send notifications using DBus. container_info()
and
workspace_info()
uses it to display information about the container
or the tree for a workspace.
polybar: the status bar
i3 bundles i3bar, a versatile status bar, but I have opted for
Polybar. A wrapper script runs one instance for
each monitor.
The first module is the built-in support for i3 workspaces. To not
have to remember which application is running in a workspace, the i3
companion renames workspaces to include an icon for each application.
This is done in the workspace_rename()
function. The icons are from
the Font Awesome project. I maintain a mapping between applications
and icons. This is a bit cumbersome but it looks great.
For CPU, memory, brightness, battery, disk, and audio volume, I am
relying on the built-in modules. Polybar s wrapper script generates the list of filesystems to monitor and they get only
displayed when available space is low. The battery widget turns red
and blinks slowly when running out of power. Check my Polybar
configuration for more details.
For Bluetooh, network, and notification statuses, I am using Polybar s
ipc
module: the next version of Polybar can receive
an arbitrary text on an IPC socket. The module is defined with a
single hook to be executed at the start to restore the latest status.
[module/network]
type = custom/ipc
hook-0 = cat $XDG_RUNTIME_DIR/i3/network.txt 2> /dev/null
initial = 1
It can be updated with polybar-msg action "#network.send.XXXX"
. In
the i3 companion, the @polybar()
decorator takes the string
returned by a function and pushes the update through the IPC socket.
The i3 companion reacts to DBus signals to update the Bluetooth and
network icons. The @on()
decorator accepts a DBusSignal()
object:
@on(
StartEvent,
DBusSignal(
path="/org/bluez",
interface="org.freedesktop.DBus.Properties",
member="PropertiesChanged",
signature="sa sv as",
onlyif=lambda args: (
args[0] == "org.bluez.Device1"
and "Connected" in args[1]
or args[0] == "org.bluez.Adapter1"
and "Powered" in args[1]
),
),
)
@retry(2)
@debounce(0.2)
@polybar("bluetooth")
async def bluetooth_status(i3, event, *args):
"""Update bluetooth status for Polybar."""
The middle of the bar is occupied by the date and a weather forecast.
The latest also uses the IPC mechanism, but the source is a Python
script triggered by a timer.
I don t use the system tray integrated with Polybar. The embedded
icons usually look horrible and they all behave differently. A few
years back, Gnome has removed the system tray. Most of the
problems are fixed by the DBus-based Status Notifier Item
protocol also known as Application Indicators or Ayatana
Indicators for GNOME. However, Polybar does not support this
protocol. In the i3 companion, The implementation of Bluetooth
and network icons, including displaying notifications on change, takes
about 200 lines. I got to learn a bit about how DBus works and I get exactly
the info I want.
picom: the compositor
I like having slightly transparent backgrounds for terminals and to
reduce the opacity of unfocused windows. This requires a
compositor.1 picom is a lightweight compositor. It works
well for me, but it may need some tweaking depending on your graphic
card.2 Unlike the awesome window manager, i3 does not handle
transparency, so the compositor needs to decide by itself the opacity
of each window. Check my configuration for details.
systemd: the service manager
I use systemd to start i3 and the various services around it. My
xsession script only sets some environment variables and lets
systemd handles everything else. Have a look at this article from
Micha G ral for the rationale. Notably, each component can be
easily restarted and their logs are not mangled inside the
~/.xsession-errors
file.3
I am using a two-stage setup: i3.service
depends on
xsession.target
to start services before
i3:
[Unit]
Description=X session
BindsTo=graphical-session.target
Wants=autorandr.service
Wants=dunst.socket
Wants=inputplug.service
Wants=picom.service
Wants=pulseaudio.socket
Wants=policykit-agent.service
Wants=redshift.service
Wants=spotify-clean.timer
Wants=ssh-agent.service
Wants=xiccd.service
Wants=xsettingsd.service
Wants=xss-lock.service
Then, i3 executes the second stage by invoking the
i3-session.target
:
[Unit]
Description=i3 session
BindsTo=graphical-session.target
Wants=wallpaper.service
Wants=wallpaper.timer
Wants=polybar-weather.service
Wants=polybar-weather.timer
Wants=polybar.service
Wants=i3-companion.service
Wants=misc-x.service
Have a look on my configuration files for more
details.
rofi: the application launcher
Rofi is an application launcher. Its appearance can be customized
through a CSS-like language and it comes with several themes. Have a
look at my configuration for mine.
It can also act as a generic menu application. I have a script
to control a media player and another one to
select the wifi network. It is quite a flexible
application.
xss-lock and i3lock: the screen locker
i3lock is a simple screen locker. xss-lock invokes it reliably
on inactivity or before a system suspend. For inactivity, it uses the
XScreenSaver events. The delay is configured using the xset s
command. The locker can be invoked immediately with xset s activate
.
X11 applications know how to prevent the screen saver from running. I
have also developed a small dimmer application that is executed 20
seconds before the locker to give me a chance to move the mouse if I
am not away.4 Have a look at my configuration
script.
The remaining components
-
autorandr is a tool to detect the connected display, match them
against a set of profiles, and configure them with
xrandr
.
-
inputplug executes a script for each new mouse and keyboard
plugged. This is quite useful to load the appropriate the keyboard
map. See my configuration.
-
xsettingsd provides settings to X11 applications, not unlike
xrdb but it notifies applications for changes. The main use is
to configure the Gtk and DPI settings. See my article on HiDPI
support on Linux with X11.
-
Redshift adjusts the color temperature of the screen according
to the time of day.
-
maim is a utility to take screenshots. I use Prt Scn
to trigger a screenshot of a window or a specific area and
Mod+Prt Scn to capture the whole desktop to a
file. Check the helper script for details.
-
I have a collection of wallpapers I rotate every hour. A
script selects them using advanced machine learning
algorithms and stitches them together on multi-screen setups. The
selected wallpaper is reused by i3lock.
-
Apart from the eye candy, a compositor also helps to get
tear-free video playbacks.
-
My configuration works with both Haswell (2014) and Whiskey
Lake (2018) Intel GPUs. It also works with AMD GPU based on the
Polaris chipset (2017).
-
You cannot manage two different displays this way e.g.
:0
and :1
. In the first implementation, I did try to
parametrize each service with the associated display, but this is
useless: there is only one DBus user session and many services
rely on it. For example, you cannot run two notification daemons.
-
I have only discovered later that XSecureLock ships
such a dimmer with a similar implementation. But mine has a cool
countdown!
Do not add further complexity when it can be avoided. We are generally happy with the feature set of i3 and instead focus on fixing bugs and maintaining it for stability. New features will therefore only be considered if the benefit outweighs the additional complexity, and we encourage users to implement features using the IPC whenever possible. Introduction to the i3 window managerWhile this is not as powerful as an embedded language, it is enough for many cases. Moreover, as high-level features may be opinionated, delegating them to small, loosely coupled pieces of code keeps them more maintainable. Libraries exist for this purpose in several languages. Users have published many scripts to extend i3: automatic layout and window promotion to mimic the behavior of other tiling window managers, window swallowing to put a new app on top of the terminal launching it, and cycling between windows with Alt+Tab. Instead of maintaining a script for each feature, I have centralized everything into a single Python process,
i3-companion
using asyncio and the
i3ipc-python library. Each feature is self-contained into a
function. It implements the following components:
- make a workspace exclusive to an application
- When a workspace contains Emacs or Firefox, I would like other
applications to move to another workspace, except for the terminal
which is allowed to intrude into any workspace. The
workspace_exclusive()
function monitors new windows and moves them if needed to an empty workspace or to one with the same application already running. - implement a Quake console
- The
quake_console()
function implements a drop-down console available from any workspace. It can be toggled with Mod+ . This is implemented as a scratchpad window. - back and forth workspace switching on the same output
- With the
workspace back_and_forth
command, we can ask i3 to switch to the previous workspace. However, this feature is not restricted to the current output. I prefer to have one keybinding to switch to the workspace on the next output and one keybinding to switch to the previous workspace on the same output. This behavior is implemented in theprevious_workspace()
function by keeping a per-output history of the focused workspaces. - create a new empty workspace or move a window to an empty workspace
- To create a new empty workspace or move a window to an empty
workspace, you have to locate a free slot and use
workspace number 4
ormove container to workspace number 4
. Thenew_workspace()
function finds a free number and use it as the target workspace. - restart some services on output change
- When adding or removing an output, some actions need to be executed:
refresh the wallpaper, restart some components unable to adapt their
configuration on their own, etc. i3 triggers an event for this
purpose. The
output_update()
function also takes an extra step to coalesce multiple consecutive events and to check if there is a real change with the low-level library xcffib.
@on(CommandEvent("previous-workspace"), I3Event.WORKSPACE_FOCUS) async def previous_workspace(i3, event): """Go to previous workspace on the same output."""
CommandEvent()
event class is my way to send a command to the
companion, using either i3-msg -t send_tick
or binding a key to a
nop
command. The latter is used to avoid spawning a shell and a
i3-msg
process just to send a message. The companion listens to
binding events and checks if this is a nop
command.
bindsym $mod+Tab nop "previous-workspace"
@debounce()
to
coalesce multiple consecutive calls, @static()
to define a static
variable, and @retry()
to retry a function on failure. The whole
script is a bit more than 1000 lines. I think this is
worth a read as I am quite happy with the result.
dunst: the notification daemon
Unlike the awesome window manager, i3 does not come with a built-in
notification system. Dunst is a lightweight notification daemon. I
am running a modified version with HiDPI support for X11 and
recursive icon lookup. The i3 companion has a helper function,
notify()
, to send notifications using DBus. container_info()
and
workspace_info()
uses it to display information about the container
or the tree for a workspace.
polybar: the status bar
i3 bundles i3bar, a versatile status bar, but I have opted for
Polybar. A wrapper script runs one instance for
each monitor.
The first module is the built-in support for i3 workspaces. To not
have to remember which application is running in a workspace, the i3
companion renames workspaces to include an icon for each application.
This is done in the workspace_rename()
function. The icons are from
the Font Awesome project. I maintain a mapping between applications
and icons. This is a bit cumbersome but it looks great.
For CPU, memory, brightness, battery, disk, and audio volume, I am
relying on the built-in modules. Polybar s wrapper script generates the list of filesystems to monitor and they get only
displayed when available space is low. The battery widget turns red
and blinks slowly when running out of power. Check my Polybar
configuration for more details.
For Bluetooh, network, and notification statuses, I am using Polybar s
ipc
module: the next version of Polybar can receive
an arbitrary text on an IPC socket. The module is defined with a
single hook to be executed at the start to restore the latest status.
[module/network]
type = custom/ipc
hook-0 = cat $XDG_RUNTIME_DIR/i3/network.txt 2> /dev/null
initial = 1
It can be updated with polybar-msg action "#network.send.XXXX"
. In
the i3 companion, the @polybar()
decorator takes the string
returned by a function and pushes the update through the IPC socket.
The i3 companion reacts to DBus signals to update the Bluetooth and
network icons. The @on()
decorator accepts a DBusSignal()
object:
@on(
StartEvent,
DBusSignal(
path="/org/bluez",
interface="org.freedesktop.DBus.Properties",
member="PropertiesChanged",
signature="sa sv as",
onlyif=lambda args: (
args[0] == "org.bluez.Device1"
and "Connected" in args[1]
or args[0] == "org.bluez.Adapter1"
and "Powered" in args[1]
),
),
)
@retry(2)
@debounce(0.2)
@polybar("bluetooth")
async def bluetooth_status(i3, event, *args):
"""Update bluetooth status for Polybar."""
The middle of the bar is occupied by the date and a weather forecast.
The latest also uses the IPC mechanism, but the source is a Python
script triggered by a timer.
I don t use the system tray integrated with Polybar. The embedded
icons usually look horrible and they all behave differently. A few
years back, Gnome has removed the system tray. Most of the
problems are fixed by the DBus-based Status Notifier Item
protocol also known as Application Indicators or Ayatana
Indicators for GNOME. However, Polybar does not support this
protocol. In the i3 companion, The implementation of Bluetooth
and network icons, including displaying notifications on change, takes
about 200 lines. I got to learn a bit about how DBus works and I get exactly
the info I want.
picom: the compositor
I like having slightly transparent backgrounds for terminals and to
reduce the opacity of unfocused windows. This requires a
compositor.1 picom is a lightweight compositor. It works
well for me, but it may need some tweaking depending on your graphic
card.2 Unlike the awesome window manager, i3 does not handle
transparency, so the compositor needs to decide by itself the opacity
of each window. Check my configuration for details.
systemd: the service manager
I use systemd to start i3 and the various services around it. My
xsession script only sets some environment variables and lets
systemd handles everything else. Have a look at this article from
Micha G ral for the rationale. Notably, each component can be
easily restarted and their logs are not mangled inside the
~/.xsession-errors
file.3
I am using a two-stage setup: i3.service
depends on
xsession.target
to start services before
i3:
[Unit]
Description=X session
BindsTo=graphical-session.target
Wants=autorandr.service
Wants=dunst.socket
Wants=inputplug.service
Wants=picom.service
Wants=pulseaudio.socket
Wants=policykit-agent.service
Wants=redshift.service
Wants=spotify-clean.timer
Wants=ssh-agent.service
Wants=xiccd.service
Wants=xsettingsd.service
Wants=xss-lock.service
Then, i3 executes the second stage by invoking the
i3-session.target
:
[Unit]
Description=i3 session
BindsTo=graphical-session.target
Wants=wallpaper.service
Wants=wallpaper.timer
Wants=polybar-weather.service
Wants=polybar-weather.timer
Wants=polybar.service
Wants=i3-companion.service
Wants=misc-x.service
Have a look on my configuration files for more
details.
rofi: the application launcher
Rofi is an application launcher. Its appearance can be customized
through a CSS-like language and it comes with several themes. Have a
look at my configuration for mine.
It can also act as a generic menu application. I have a script
to control a media player and another one to
select the wifi network. It is quite a flexible
application.
xss-lock and i3lock: the screen locker
i3lock is a simple screen locker. xss-lock invokes it reliably
on inactivity or before a system suspend. For inactivity, it uses the
XScreenSaver events. The delay is configured using the xset s
command. The locker can be invoked immediately with xset s activate
.
X11 applications know how to prevent the screen saver from running. I
have also developed a small dimmer application that is executed 20
seconds before the locker to give me a chance to move the mouse if I
am not away.4 Have a look at my configuration
script.
The remaining components
-
autorandr is a tool to detect the connected display, match them
against a set of profiles, and configure them with
xrandr
.
-
inputplug executes a script for each new mouse and keyboard
plugged. This is quite useful to load the appropriate the keyboard
map. See my configuration.
-
xsettingsd provides settings to X11 applications, not unlike
xrdb but it notifies applications for changes. The main use is
to configure the Gtk and DPI settings. See my article on HiDPI
support on Linux with X11.
-
Redshift adjusts the color temperature of the screen according
to the time of day.
-
maim is a utility to take screenshots. I use Prt Scn
to trigger a screenshot of a window or a specific area and
Mod+Prt Scn to capture the whole desktop to a
file. Check the helper script for details.
-
I have a collection of wallpapers I rotate every hour. A
script selects them using advanced machine learning
algorithms and stitches them together on multi-screen setups. The
selected wallpaper is reused by i3lock.
-
Apart from the eye candy, a compositor also helps to get
tear-free video playbacks.
-
My configuration works with both Haswell (2014) and Whiskey
Lake (2018) Intel GPUs. It also works with AMD GPU based on the
Polaris chipset (2017).
-
You cannot manage two different displays this way e.g.
:0
and :1
. In the first implementation, I did try to
parametrize each service with the associated display, but this is
useless: there is only one DBus user session and many services
rely on it. For example, you cannot run two notification daemons.
-
I have only discovered later that XSecureLock ships
such a dimmer with a similar implementation. But mine has a cool
countdown!
workspace_rename()
function. The icons are from
the Font Awesome project. I maintain a mapping between applications
and icons. This is a bit cumbersome but it looks great.
For CPU, memory, brightness, battery, disk, and audio volume, I am
relying on the built-in modules. Polybar s wrapper script generates the list of filesystems to monitor and they get only
displayed when available space is low. The battery widget turns red
and blinks slowly when running out of power. Check my Polybar
configuration for more details.
For Bluetooh, network, and notification statuses, I am using Polybar s
ipc
module: the next version of Polybar can receive
an arbitrary text on an IPC socket. The module is defined with a
single hook to be executed at the start to restore the latest status.
[module/network] type = custom/ipc hook-0 = cat $XDG_RUNTIME_DIR/i3/network.txt 2> /dev/null initial = 1
polybar-msg action "#network.send.XXXX"
. In
the i3 companion, the @polybar()
decorator takes the string
returned by a function and pushes the update through the IPC socket.
The i3 companion reacts to DBus signals to update the Bluetooth and
network icons. The @on()
decorator accepts a DBusSignal()
object:
@on( StartEvent, DBusSignal( path="/org/bluez", interface="org.freedesktop.DBus.Properties", member="PropertiesChanged", signature="sa sv as", onlyif=lambda args: ( args[0] == "org.bluez.Device1" and "Connected" in args[1] or args[0] == "org.bluez.Adapter1" and "Powered" in args[1] ), ), ) @retry(2) @debounce(0.2) @polybar("bluetooth") async def bluetooth_status(i3, event, *args): """Update bluetooth status for Polybar."""
picom: the compositor
I like having slightly transparent backgrounds for terminals and to
reduce the opacity of unfocused windows. This requires a
compositor.1 picom is a lightweight compositor. It works
well for me, but it may need some tweaking depending on your graphic
card.2 Unlike the awesome window manager, i3 does not handle
transparency, so the compositor needs to decide by itself the opacity
of each window. Check my configuration for details.
systemd: the service manager
I use systemd to start i3 and the various services around it. My
xsession script only sets some environment variables and lets
systemd handles everything else. Have a look at this article from
Micha G ral for the rationale. Notably, each component can be
easily restarted and their logs are not mangled inside the
~/.xsession-errors
file.3
I am using a two-stage setup: i3.service
depends on
xsession.target
to start services before
i3:
[Unit]
Description=X session
BindsTo=graphical-session.target
Wants=autorandr.service
Wants=dunst.socket
Wants=inputplug.service
Wants=picom.service
Wants=pulseaudio.socket
Wants=policykit-agent.service
Wants=redshift.service
Wants=spotify-clean.timer
Wants=ssh-agent.service
Wants=xiccd.service
Wants=xsettingsd.service
Wants=xss-lock.service
Then, i3 executes the second stage by invoking the
i3-session.target
:
[Unit]
Description=i3 session
BindsTo=graphical-session.target
Wants=wallpaper.service
Wants=wallpaper.timer
Wants=polybar-weather.service
Wants=polybar-weather.timer
Wants=polybar.service
Wants=i3-companion.service
Wants=misc-x.service
Have a look on my configuration files for more
details.
rofi: the application launcher
Rofi is an application launcher. Its appearance can be customized
through a CSS-like language and it comes with several themes. Have a
look at my configuration for mine.
It can also act as a generic menu application. I have a script
to control a media player and another one to
select the wifi network. It is quite a flexible
application.
xss-lock and i3lock: the screen locker
i3lock is a simple screen locker. xss-lock invokes it reliably
on inactivity or before a system suspend. For inactivity, it uses the
XScreenSaver events. The delay is configured using the xset s
command. The locker can be invoked immediately with xset s activate
.
X11 applications know how to prevent the screen saver from running. I
have also developed a small dimmer application that is executed 20
seconds before the locker to give me a chance to move the mouse if I
am not away.4 Have a look at my configuration
script.
The remaining components
-
autorandr is a tool to detect the connected display, match them
against a set of profiles, and configure them with
xrandr
.
-
inputplug executes a script for each new mouse and keyboard
plugged. This is quite useful to load the appropriate the keyboard
map. See my configuration.
-
xsettingsd provides settings to X11 applications, not unlike
xrdb but it notifies applications for changes. The main use is
to configure the Gtk and DPI settings. See my article on HiDPI
support on Linux with X11.
-
Redshift adjusts the color temperature of the screen according
to the time of day.
-
maim is a utility to take screenshots. I use Prt Scn
to trigger a screenshot of a window or a specific area and
Mod+Prt Scn to capture the whole desktop to a
file. Check the helper script for details.
-
I have a collection of wallpapers I rotate every hour. A
script selects them using advanced machine learning
algorithms and stitches them together on multi-screen setups. The
selected wallpaper is reused by i3lock.
-
Apart from the eye candy, a compositor also helps to get
tear-free video playbacks.
-
My configuration works with both Haswell (2014) and Whiskey
Lake (2018) Intel GPUs. It also works with AMD GPU based on the
Polaris chipset (2017).
-
You cannot manage two different displays this way e.g.
:0
and :1
. In the first implementation, I did try to
parametrize each service with the associated display, but this is
useless: there is only one DBus user session and many services
rely on it. For example, you cannot run two notification daemons.
-
I have only discovered later that XSecureLock ships
such a dimmer with a similar implementation. But mine has a cool
countdown!
~/.xsession-errors
file.3
I am using a two-stage setup: i3.service
depends on
xsession.target
to start services before
i3:
[Unit] Description=X session BindsTo=graphical-session.target Wants=autorandr.service Wants=dunst.socket Wants=inputplug.service Wants=picom.service Wants=pulseaudio.socket Wants=policykit-agent.service Wants=redshift.service Wants=spotify-clean.timer Wants=ssh-agent.service Wants=xiccd.service Wants=xsettingsd.service Wants=xss-lock.service
i3-session.target
:
[Unit] Description=i3 session BindsTo=graphical-session.target Wants=wallpaper.service Wants=wallpaper.timer Wants=polybar-weather.service Wants=polybar-weather.timer Wants=polybar.service Wants=i3-companion.service Wants=misc-x.service
rofi: the application launcher
Rofi is an application launcher. Its appearance can be customized
through a CSS-like language and it comes with several themes. Have a
look at my configuration for mine.
It can also act as a generic menu application. I have a script
to control a media player and another one to
select the wifi network. It is quite a flexible
application.
xss-lock and i3lock: the screen locker
i3lock is a simple screen locker. xss-lock invokes it reliably
on inactivity or before a system suspend. For inactivity, it uses the
XScreenSaver events. The delay is configured using the xset s
command. The locker can be invoked immediately with xset s activate
.
X11 applications know how to prevent the screen saver from running. I
have also developed a small dimmer application that is executed 20
seconds before the locker to give me a chance to move the mouse if I
am not away.4 Have a look at my configuration
script.
The remaining components
-
autorandr is a tool to detect the connected display, match them
against a set of profiles, and configure them with
xrandr
.
-
inputplug executes a script for each new mouse and keyboard
plugged. This is quite useful to load the appropriate the keyboard
map. See my configuration.
-
xsettingsd provides settings to X11 applications, not unlike
xrdb but it notifies applications for changes. The main use is
to configure the Gtk and DPI settings. See my article on HiDPI
support on Linux with X11.
-
Redshift adjusts the color temperature of the screen according
to the time of day.
-
maim is a utility to take screenshots. I use Prt Scn
to trigger a screenshot of a window or a specific area and
Mod+Prt Scn to capture the whole desktop to a
file. Check the helper script for details.
-
I have a collection of wallpapers I rotate every hour. A
script selects them using advanced machine learning
algorithms and stitches them together on multi-screen setups. The
selected wallpaper is reused by i3lock.
-
Apart from the eye candy, a compositor also helps to get
tear-free video playbacks.
-
My configuration works with both Haswell (2014) and Whiskey
Lake (2018) Intel GPUs. It also works with AMD GPU based on the
Polaris chipset (2017).
-
You cannot manage two different displays this way e.g.
:0
and :1
. In the first implementation, I did try to
parametrize each service with the associated display, but this is
useless: there is only one DBus user session and many services
rely on it. For example, you cannot run two notification daemons.
-
I have only discovered later that XSecureLock ships
such a dimmer with a similar implementation. But mine has a cool
countdown!
xset s
command. The locker can be invoked immediately with xset s activate
.
X11 applications know how to prevent the screen saver from running. I
have also developed a small dimmer application that is executed 20
seconds before the locker to give me a chance to move the mouse if I
am not away.4 Have a look at my configuration
script.
The remaining components
-
autorandr is a tool to detect the connected display, match them
against a set of profiles, and configure them with
xrandr
.
-
inputplug executes a script for each new mouse and keyboard
plugged. This is quite useful to load the appropriate the keyboard
map. See my configuration.
-
xsettingsd provides settings to X11 applications, not unlike
xrdb but it notifies applications for changes. The main use is
to configure the Gtk and DPI settings. See my article on HiDPI
support on Linux with X11.
-
Redshift adjusts the color temperature of the screen according
to the time of day.
-
maim is a utility to take screenshots. I use Prt Scn
to trigger a screenshot of a window or a specific area and
Mod+Prt Scn to capture the whole desktop to a
file. Check the helper script for details.
-
I have a collection of wallpapers I rotate every hour. A
script selects them using advanced machine learning
algorithms and stitches them together on multi-screen setups. The
selected wallpaper is reused by i3lock.
-
Apart from the eye candy, a compositor also helps to get
tear-free video playbacks.
-
My configuration works with both Haswell (2014) and Whiskey
Lake (2018) Intel GPUs. It also works with AMD GPU based on the
Polaris chipset (2017).
-
You cannot manage two different displays this way e.g.
:0
and :1
. In the first implementation, I did try to
parametrize each service with the associated display, but this is
useless: there is only one DBus user session and many services
rely on it. For example, you cannot run two notification daemons.
-
I have only discovered later that XSecureLock ships
such a dimmer with a similar implementation. But mine has a cool
countdown!
xrandr
.
- Apart from the eye candy, a compositor also helps to get tear-free video playbacks.
- My configuration works with both Haswell (2014) and Whiskey Lake (2018) Intel GPUs. It also works with AMD GPU based on the Polaris chipset (2017).
-
You cannot manage two different displays this way e.g.
:0
and:1
. In the first implementation, I did try to parametrize each service with the associated display, but this is useless: there is only one DBus user session and many services rely on it. For example, you cannot run two notification daemons. - I have only discovered later that XSecureLock ships such a dimmer with a similar implementation. But mine has a cool countdown!